// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package server

import (
	"encoding/binary"
	"epg/stats"

	dmysql "github.com/go-sql-driver/mysql"

	"github.com/zeast/logs"
)

/******************************************************************************
*                           Packets Process                                   *
******************************************************************************/
// Packets documentation:
// http://dev.mysql.com/doc/internals/en/client-server-protocol.html

func (c *Client) writeResultPackets(payloads [][]byte) error {
	var err error

	//stats the packet size.
	total := 0
	for i := 0; i < len(payloads); i++ {
		total += len(payloads[i])
	}
	stats.Stater.Gauge("packet.write", uint64(total))

	err = c.io.writeMultiPacket(c, payloads)
	c.io.sequence = 0
	return err
}

// Ok Packet
// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet
func (mc *mysqlConn) handleOkPacket(data []byte) error {
	var n, m int

	// 0x00 [1 byte]

	// Affected rows [Length Coded Binary]
	mc.affectedRows, _, n = readLengthEncodedInteger(data[1:])

	// Insert id [Length Coded Binary]
	mc.insertID, _, m = readLengthEncodedInteger(data[1+n:])

	// server_status [2 bytes]
	mc.status = readStatus(data[1+n+m : 1+n+m+2])
	// if err := mc.discardResults(); err != nil {
	// 	return err
	// }

	// warning count [2 bytes]
	if !mc.strict {
		return nil
	}

	pos := 1 + n + m + 2
	if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 {
		logs.Warn("mc.getWarnings()")
		return nil
	}
	return nil
}

/******************************************************************************
*                             Command Packets                                 *
******************************************************************************/

func (mc *mysqlConn) writeCommandPacket(command byte) error {
	// Reset Packet Sequence
	mc.io.sequence = 0
	data := mc.buf.GetSize(4 + 1)
	if data == nil {
		// can not take the buffer. Something must be wrong with the connection
		return dmysql.ErrBusyBuffer
	}

	// Add command byte
	data[4] = command

	// Send CMD packet
	return mc.io.writePacket(data)
}

func (mc *mysqlConn) writePacketByte(command byte, arg []byte) error {
	// Reset Packet Sequence
	mc.io.sequence = 0

	pktLen := 1 + len(arg)
	data := mc.buf.GetSize(pktLen + 4)
	if data == nil {
		// can not take the buffer. Something must be wrong with the connection
		return dmysql.ErrBusyBuffer
	}

	// Add command byte
	data[4] = command

	// Add arg
	copy(data[5:], arg)

	// Send CMD packet
	return mc.io.writePacket(data)
}

func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
	// Reset Packet Sequence
	mc.io.sequence = 0

	pktLen := 1 + len(arg)
	data := mc.buf.GetSize(pktLen + 4)
	if data == nil {
		// can not take the buffer. Something must be wrong with the connection
		return dmysql.ErrBusyBuffer
	}

	// Add command byte
	data[4] = command

	// Add arg
	copy(data[5:], arg)

	// Send CMD packet
	return mc.io.writePacket(data)
}

func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
	// Reset Packet Sequence
	mc.io.sequence = 0

	data := mc.buf.GetSize(4 + 1 + 4)
	if data == nil {
		// can not take the buffer. Something must be wrong with the connection
		return dmysql.ErrBusyBuffer
	}

	// Add command byte
	data[4] = command

	// Add arg [32 bit]
	data[5] = byte(arg)
	data[6] = byte(arg >> 8)
	data[7] = byte(arg >> 16)
	data[8] = byte(arg >> 24)

	// Send CMD packet
	return mc.io.writePacket(data)
}

func (mc *mysqlConn) WriteCommandPacketUint32(command byte, arg uint32) error {
	return mc.writeCommandPacketUint32(command,arg)
}
